/*
**  File: AquaFuncts_cv.c
**
**  This file is part of the AQUA program suite, which is being
**  developed in the NMR Spectroscopy Department, Bijvoet Center for 
**  Biomolecular Research, Utrecht. 
**
**
**  AUTHOR(S) : Ton Rullmann
**  VERSION   : 1.2.1
**  DATE      : Mar 27, 1997
**
**  The functions in this package process non-Aqua molecular coordinate
**  data files. The data are stored in a series of arrays (see the globally
**  declared pointers), and subsequently transferred to an Aqua strucset
**  data structure.
**
**  Externally available functions:
**
**  Alloc_cv:      allocate memory for arrays
**  Free_cv:       deallocate memory for arrays
**  ReadFil_cv:    read a data file using a routine from cv_subs.f 
**  ReadDummy_cv:  simulate ReadFil_cv by generating dummy atoms
**  ToAqua_cv:     transfer data to Aqua strucset
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "Compiler.h"
#include "General.h"

#include "AquaMacros.h"
#include "AquaTypes.h"

/****************  function prototypes  ****************/

#ifdef CVALL
#include "cv_subs.h"
#endif
#include "AquaFuncts.h"
#include "AquaFuncts_io.h"
#include "Functs.h"

#include "AquaFuncts_cv.h"

static void rddum( const int count, float x[], float y[], float z[],
                   int resno[], char resnam[], int atono[], char atonam[],
                   char atoel[]  );
/* static void prtdum( const int count, float *x, float *y, float *z,
                    int *resno, char *resnam, int *atono, char *atonam,
                    char *atoel  ); */
static Atom *FillAtoms_cv( const int atom_count, const Boolean store_int  );
static Coord *FillCoords_cv( const int atom_count );

/****************  globals  ****************/

Boolean        alloc_cv = false;            /*       ...     */
char           *header;                     /*       ...     */
float          *x, *y, *z;                  /*    export to  */
int            *atono, *resno;              /* AquaFuncts_io */
char           *atonam, *btonam, *resnam;   /*       ...     */
char           *chain, *insert, *atoel;     /*       ...     */

extern Card    msg_string;                  /* import from Functs */
extern int      terseness;                  /* import from Functs */


#define MAXHEADER     10                    /* should be same as in AquaFuncts_io */
#define size_HEADER   size_LINE

/* BEGIN_EXTH */

#ifdef CVALL

/****************  ReadFil_cv  ****************/
/*
**  Read a coordinate data file, using a routine from cvall_subs.f
*/

Status ReadFil_cv( char *filnam, const Filtyp type, int count,
                   int *fil_struc_num, int *nerr )
{
    int     max_header = MAXHEADER;
    int     iunit = 10;
    int     nread;
    Boolean err;

/* allocate memory */

    if ( !alloc_cv )
        Alloc_cv( count );
        
/* prepare for using cvall routines (cv_subs.f) */

    init_cv_( &iunit, filnam, header, &max_header, &count, 
              (int)size_FILNAM, (int)size_HEADER );

/* read a file - assume 1 structure for now!! */
    
    (*fil_struc_num)++;
    
    switch ( type )
    {
        case pdb_type:
        case pdbn_type:
            nread = rdpdb_( &iunit, header, x, y, z, resno, resnam, atono,
                    atonam, chain, 
                    (int)size_HEADER, (int)size_ID, (int)size_ID,
                    (int)size_ID );
            break;
        default:
	    puts( " * Reading of this data type not implemented in AquaFuncts_cv" );
            break;
    }

    err = ( nread <= 0 ) || ( nread != count );

    if ( err )
        printf( " * File %s: read %i atoms  -- ERROR\n", filnam, nread );
    else {
        if ( terseness < 6 ) {
            printf( "File %s: read %i atoms\n", filnam, nread );
        }
    }

    close_cv_( &iunit );
    *nerr = nread;
    
    return( err ? read_err : status_ok );
}

#endif

/****************  ReadDummy_cv  ****************/
/*
**  Simulate ReadFil_cv by generating dummy atoms.
*/

Status ReadDummy_cv( const int count, int *fil_struc_num )
{
    if ( !alloc_cv )
        Alloc_cv( count );
        
    (*fil_struc_num)++;
    
    rddum( count, x, y, z, resno, resnam, atono, atonam, atoel );
    strcpy( header, "Dummy molecule");
/*
    prtdum( count, x, y, z, resno, resnam, atono, atonam, atoel );
*/
    return( status_ok );
}

/****************  ToAqua_cv  ****************/
/*
**  Convert to proper Aqua data structure, using the external atom name.
**  If <store_int> the internal atom name will be filled from <btonam>.
**  Cf. StrucsetCreate.
*/

void ToAqua_cv( Strucset *set, char *filnam, const Filtyp type, 
                const int atom_count, const int fil_struc_num, 
		Boolean store_int )
{
    char   *fct_name = "ToAqua_cv";
    size_t len;
    Mol    *molptr;
    Struc  *strucptr;
            
    if ( set->struc_count == 0 )
    {
/* allocate and fill molecule - data from first input file */
        if ( terseness < 6 ) {
            STATUS( "allocating new molecule" );
        }
        molptr = CREATE_NEW( Mol, 1 );
        molptr->atoms = FillAtoms_cv( atom_count, store_int );
        molptr->atom_count = atom_count;
        molptr->inp_filtyp = type;
        strcpy( molptr->inp_filnam, filnam );
        len = LenChars( header, size_HEADER ) + 1;
        len = ( len < size_LINE ? len : size_LINE );
        memcpy( molptr->ident, header, len );
        molptr->ident[ len-1 ] = '\0';
        memcpy( set->ident, header, len );
        set->ident[ len-1 ] = '\0';
	strcpy( set->derived, "Atoms derived from: " );
	len = strlen( set->derived ) + strlen( molptr->inp_filnam );
	len = ( len < size_LINE-1 ? len : size_LINE-1 );
	strncat( set->derived, molptr->inp_filnam, len - strlen( set->derived ) );
    
        set->atom_count = atom_count;
        set->molecule = molptr;
	
	if ( store_int )
	    set->mapped = true;
	MakeResidues( set, true );
    }
    else
    {
/* compare stored molecule with data from next input file */
        if ( terseness < 6 ) {
	    STATUS( "no checking of 2nd, 3rd ff. molecule YET" );
        }
    }

/* allocate and fill the new structure */
    if ( terseness < 6 ) {
        STATUS( "allocating new structure" );
    }
    strucptr = CREATE_NEW( Struc, 1 );
    if ( set->struc_count == 0 )
        set->fst_struc = strucptr;
    else
        set->lst_struc->next_struc = strucptr;
    set->lst_struc = strucptr;
    set->struc_count++;
    
    strucptr->coords = FillCoords_cv( atom_count );
    strucptr->atom_count = atom_count;
    strucptr->struc_num = set->struc_count;   /* sequential model number, starting at 1 */
    strucptr->fil_struc_num = fil_struc_num;
    strcpy( strucptr->inp_filnam, filnam );
    len = LenChars( header, size_HEADER ) + 1;
    len = ( len < size_LINE ? len : size_LINE );
    memcpy( strucptr->ident, header, len );
    strucptr->ident[ len-1 ] = '\0';
}

/****************  Alloc_cv  ****************/
/*
**  Allocate the memory for use by ReadFil_cv
*/

void Alloc_cv( const int count )
{
    char *fct_name = "Alloc_cv";

    if ( alloc_cv )
        return;

    header = CREATE_NEW( char, MAXHEADER*size_HEADER );
    x = CREATE_NEW( float, count );
    y = CREATE_NEW( float, count );
    z = CREATE_NEW( float, count );
    atono = CREATE_NEW( int, count );
    resno = CREATE_NEW( int, count );
    atonam = CREATE_NEW( char, count*size_ID );
    btonam = CREATE_NEW( char, count*size_ID );
    atoel  = CREATE_NEW( char, count*size_ID );
    resnam = CREATE_NEW( char, count*size_ID );
    chain  = CREATE_NEW( char, count*size_ID );
    insert = CREATE_NEW( char, count );

    if ( !insert )
    {
	printf( " * Out of memory\n" );
	exit( 1 );
    }

    Blank( atonam, count*size_ID );
    Blank( btonam, count*size_ID );
    Blank( atoel,  count*size_ID );
    Blank( resnam, count*size_ID );
    Blank( chain,  count*size_ID );
    Blank( insert, count );
    
    alloc_cv = true;
    if ( terseness < 6 ) {
        STATUS( "memory allocated" );
    }
}

/****************  Free_cv  ****************/
/*
**  Free the memory allocated by Alloc_cv
*/

void Free_cv( void )
{
    char *fct_name = "Free_cv";

    if ( !alloc_cv )
        return;

    free( header );
    free( x );
    free( y );
    free( z );
    free( atono );
    free( resno );
    free( atonam );
    free( btonam );
    free( atoel );
    free( resnam );
    free( chain );
    free( insert );

    alloc_cv = false;
    if ( terseness < 6 ) {
        STATUS( "memory freed" );
    }
}

/* END_EXTH ----------------------- only private functions follow */

static void rddum( const int count, float x[], float y[], float z[],  
                   int resno[], char resnam[], int atono[], char atonam[],
                   char atoel[] )
{
    int         i, j = 0;
    static int  off = 0;
    char        nam[3];

    for ( i = 0; i < count; i++)
    {
        x[i]=off+0.1F*i+0.01F;
        y[i]=off+0.2F*i+0.02F;
        z[i]=off+0.3F*i+0.03F;
        atono[i]=i+1;
        resno[i]=(i+2)/2;
        Blank( &atonam[j], 5);
        Blank( &btonam[j], 5);
        Blank( &atoel[j], 5);
        Blank( &resnam[j], 5);
        Blank( &chain[j], 5);
        insert[i] = ' ';
        
        memcpy( nam, "At", 2 );
        nam[2] = atono[i] + 96;
        memcpy( &atonam[j], nam, 3 );
        
        memcpy( nam, "Rs", 2 );
        nam[2] = resno[i] + 64;
        memcpy( &resnam[j], nam, 3 );
        j += size_ID;
    }
    off++;
}

/****************  FillAtoms_cv  ****************/
/*
**  Allocate and fill atom information, using the external atom name.
**  If <store_int> the internal atom name will be filled from <btonam>.
*/

static Atom *FillAtoms_cv( const int atom_count, const Boolean store_int )
{
    char  *fct_name = "FillAtoms_cv";
    Atom  *atoms, *firstatom;
    int   i = 0;
    char  *a, *b, *el, *r, *chn, *ins;
    int   *ir;
    
    sprintf( msg_string, "allocating %i atoms in new molecule", atom_count );
    if ( terseness < 6 ) {
        STATUSm;
    }
    firstatom = CREATE_NEW( Atom, atom_count );
    if ( !firstatom )
	NOMEM( "atoms" );

    atoms = firstatom;
    a = atonam;
    b = btonam;
    el = atoel;
    r = resnam;
    chn = chain;
    ins = insert;
    ir = resno;
    while ( i++ < atom_count )
    {
        memcpy( atoms->atom_ext, a, size_ID );      /* atom name */
        if ( store_int )
            memcpy( atoms->atom_int, b, size_ID );
        memcpy( atoms->atom_element_symbol, el, size_ID ); /* atom element symbol */
                
        memcpy( atoms->res_nam, r, size_ID );       /* residue name */
        memcpy( atoms->chain, chn, size_ID );       /* chain name */
        atoms->res_insert = *ins++;                 /* insertion code */
	                                     
        atoms->res_num_orig = *ir++;                /* original residue number */
/*--    atoms->res_num = atoms->res_num_orig;  */   /* res_num may be changed later.... */

        atoms++;
        a += size_ID;
        b += size_ID;
        el += size_ID;
        r += size_ID;
        chn += size_ID;
    }
    return( firstatom );
}

/****************  FillCoords_cv  ****************/
/*
**  Allocate and fill coord information
*/

static Coord *FillCoords_cv( const int atom_count )
{
    char    *fct_name = "FillCoords_cv";
    Coord   *coords, *firstcoord;
    int     i = 0;
    float   *px, *py, *pz;
    
    if ( terseness < 6 ) {
        STATUS( "allocating coordinates in new structure" );
    }
    firstcoord = CREATE_NEW( Coord, atom_count );

    coords = firstcoord;
    px = x;
    py = y;
    pz = z;
    while ( i++ < atom_count )
    {
        coords->x = *px++;
        coords->y = *py++;
        coords->z = *pz++;
        coords++;
    }
    return( firstcoord );
}


/* END_EXTH */


/* No longer in use:
static void prtdum( const int count, float *x, float *y, float *z,  
                    int *resno, char *resnam, int *atono, char *atonam,
                    char *atoel )
{
    int   i, j = 0;

    for ( i = 0; i < count; i++)
    {
        PRINTID( &atonam[j] );
        printf( "%i", atono[i] );
        PRINTID( &resnam[j] );
        printf( "%i", resno[i] );
        putchar( '\n' );
        j += size_ID;
    }
}
*/
